'''
通过Python编程完成一个银行ATM机模拟系统，具备如下功能:
(1)登陆验证：用户输入用户名密码登陆，检测用户名是否存在以及用户名密码是否匹配；用户名密码共有三次输入机会，超过三次系统退出。
(2)菜单界面：登陆成功后显示功能操作界面，输入序号选择对应功能。
(3)用户注册：用户可以输入用户名和密码创建自己的账号，并输入电话号码等信息，如果用户名存在则让用户重新输入用户名。注册后免费赠送5000元余额。
(4)账户管理：用户可以随时查看自己的账户余额。用户可以输入其他账户用户名，实现转账功能；转账时用户名必须存在，否则提示异常。用户也可以模拟实现存取款功能。
(5)用户名和密码以及账户信息等必须永久保存。且基于命令行完成，不需要开发GUI界面。
'''
'''
usercs(1)()
usercs(2)(2)
'''
'''
{'zhangsan':{'passwd':'123456','balance':9999},...}
装饰器
'''

from functools import wraps
import pickle
import  os
#全局
userDict = {}

#登陆验证
def loginVerify():
    username = ''
    print("登陆".center(20,'*'))
    for i in range(3):
        username =  input('用户名: ').strip()
        password =  input('密码: ').strip()
        if userDict.get(username) and userDict.get(username)['passwd'] == password:
            print('登录成功!')
            break
        print('用户名或密码错误!请重试,超过三次退出系统!..%s..' %(i+1))
    else:
        print('错误次数过多,退出登陆!')
        return
        #exit(-1)
    return username


#持久化
def persistFile(fname,action):
    #global  userDict
    if action == 'dump':
        if userDict:
            with open(fname,'wb') as fobj:
                pickle.dump(userDict,fobj)
    else:
        try:
            with open(fname,'rb') as fobj:
                userDict.update(pickle.load(fobj))
        except EOFError:
            pass

def userAction(opt):
    #用户注册
    def userReg():
        print("注册".center(20, '*'))
        while True:
            username = input('用户名: ').strip()
            if username in userDict.keys():
                print("用户名已经存在，请重新输入！")
                continue
            break
        password = input('密码: ').strip()
        while True:
            phone = input("手机: ").strip()
            if not phone.isdigit() and len(phone) != 11:
                print("请输入正确的手机号!")
                continue
            break
        print("注册成功！赠送5000金额！")
        userDict.update({username:{'passwd':password,'phone':phone,'balance':5000}})
        #print(userDict[username])

    #账户管理
    def accManage(username,option):
        def _showBalance():
            print('用户名:',username)
            print('余额:',userDict[username]['balance'])
        def _transferAccount():
            sum = 0
            transferUser = input('请输入要转入的用户名: ').strip()
            if not userDict.get(transferUser):
                print("转入用户名不存在！")
                return
            if transferUser == username:
                print("不能转账给自身!")
                return
            while True:
                flag = True
                amount = input("请输入转账金额: ").strip()
                if not amount.isdigit():
                    print("不合法的输入!")
                    continue
                if float(amount) + sum > userDict[username]['balance']:
                    print("金额不够!")
                    flag = False
                if flag:
                    print('转账成功!')
                    prompt = '是否要继续转账!(y/n):'
                    sum += float(amount)
                else:
                    prompt = '是否要放弃转账!(y/n):'
                while True:
                    yn = input(prompt).strip().lower()
                    if yn not in ['y','n','yes','no']:
                        print("不合法的选项！")
                        continue
                    break
                if (yn in ['y','yes'] and flag) or (not flag and yn in ['n','no']):
                    continue
                else:
                    break
            if sum:
                userDict[transferUser]['balance'] += sum
                userDict[username]['balance'] -= sum
                print('当前余额:',userDict[username]['balance'])
        def _depositAmount():
            sum = 0
            while True:
                amount = input('请输入要存入的金额: ').strip()
                if not amount.isdigit():
                    print("不合法的输入!")
                    continue
                sum += float(amount)
                print('存入成功！')
                while True:
                    yn = input('是否要继续存款!(y/n):').strip().lower()
                    if yn not in ['y','n','yes','no']:
                        print("不合法的选项！")
                        continue
                    break
                if yn in ['y','yes']:
                    continue
                break
            userDict[username]['balance'] += sum
            print('当前余额: ',userDict[username]['balance'])
        def _drawAmount():
            while True:
                flag = True
                amount = input('请输入要取出的金额: ').strip()
                if not amount.isdigit():
                    print("不合法的输入!")
                    continue
                if float(amount) > userDict[username]['balance']:
                    print("金额不够!")
                    flag = False
                if flag:
                    userDict[username]['balance'] -= float(amount)
                    print('取出成功!')
                    prompt = '是否要继续取款!(y/n):'
                else:
                    prompt = '是否要放弃取款!(y/n):'
                while True:
                    yn = input(prompt).strip().lower()
                    if yn not in ['y', 'n', 'yes', 'no']:
                        print("不合法的选项！")
                        continue
                    break
                if (yn in ['y', 'yes'] and flag) or (not flag and yn in ['n', 'no']):
                    continue
                else:
                    break
            print('当前余额:', userDict[username]['balance'])
        fns = {'1': _showBalance,'2': _depositAmount,'3':_drawAmount,'4':_transferAccount}
        return fns[option]()
    fns = {1:userReg,2:accManage}
    return fns[opt]


#菜单选择
def menuChoice(showOps):
    ops = '01234' if showOps.__name__ == 'showAccOps' else '012'
    showOps()
    while True:
        cs = input("请选择: ").strip()
        if cs not in ops:
            print("无效的选项!")
            continue
        break
    return cs

#显示菜单
def showMenu(name):
    def _showMenu(fn):
        @wraps(fn)
        def wrapper():
            #print(name.center(15, '*'))
            print('{:*^{}}'.format(name,20))
            fn()
            #print(" END ".center(15, '*'))
            print('{:*^{}}'.format('END',20))
        return wrapper
    return _showMenu

# 既然用到了装饰器，那么考虑下用装饰器检验下用户是否存在呢？



@showMenu('ATM')
def showAtmOps():
    print('1  用户注册')
    print('2  账户管理')
    print('0  退出')

@showMenu('ACCOUNT')
def showAccOps():
    print('1  查看余额')
    print('2  存款')
    print('3  取款')
    print('4  转账')
    print('0  返回上一页')


def main():
    mFuncs = {'1':userAction(1),'2':userAction(2),'0':exit}
    dbFile = 'joyUser.db'
    if os.path.exists(dbFile):
        persistFile(dbFile,'load')
    print(userDict)
    #主菜单
    while True:
        cs = menuChoice(showAtmOps)
        if cs == '0':
            persistFile(dbFile,'dump')
            mFuncs[cs](0)
        elif cs == '1':
            mFuncs[cs]()
        else:
            username = loginVerify()
            if not username:
                continue
            while True:
                accs = menuChoice(showAccOps)
                if accs == '0':
                    break
                mFuncs[cs](username,accs)

if __name__ == '__main__':
    main()


